package com.solace.selenium.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.solace.selenium.config.ServiceException;
import com.solace.selenium.entity.Authorization;
import com.solace.selenium.mapper.AuthorizationMapper;
import com.solace.selenium.service.AuthorizationService;
import com.solace.selenium.utils.KeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;

@Service
@Slf4j
public class AuthorizationServiceImpl extends ServiceImpl<AuthorizationMapper, Authorization> implements AuthorizationService {
    @Override
    public String getLocalMac() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            byte[] mac = NetworkInterface.getByInetAddress(localHost).getHardwareAddress();
            // 下面代码是把mac地址拼装成String
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < mac.length; i++) {
                if (i != 0) {
                    sb.append("-");
                }
                // mac[i] & 0xFF 是为了把byte转化为正整数
                String s = Integer.toHexString(mac[i] & 0xFF);
                sb.append(s.length() == 1 ? 0 + s : s);
            }
            return sb.toString().toUpperCase();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void decryptionKey(String key) {
        Authorization authorizationVo = parseKey(key);
        Authorization authorization;
        String mac = authorizationVo.getMac();
        Assert.hasText(mac, "获取机器信息失败!");
        if (!mac.equals(getLocalMac())) {
            throw new ServiceException("授权码与本机信息不匹配");
        }
        Assert.hasText(authorizationVo.getCode(),"随机验证码获取失败");
        Integer type = authorizationVo.getType();
        Assert.notNull(type, "授权码获取失败");
        if (type <= 0 || type > 4) {
            throw new ServiceException("授权码类型不匹配");
        }
        Long time = authorizationVo.getTime();
        Assert.notNull(time, "机器码生成时间获取失败");
        Long createKeyTime = authorizationVo.getCreateKeyTime();
        Assert.notNull(createKeyTime, "授权码生成时间获取失败");

        if (time >= createKeyTime) {
            throw new ServiceException("授权码生成时间不正确");
        }
        authorization = getByIdAndCode(authorizationVo.getId(), authorizationVo.getCode(), false);
        if (authorization==null){
            throw new ServiceException("机器码查询失败");
        }
        String localCode = authorization.getCode();
        Assert.hasText(localCode,"机器码CODE未获取到");
        String code = authorizationVo.getCode();
        Assert.hasText(code,"远程机器码CODE未获取到");
        if (!localCode.equals(code)){
            throw new ServiceException("机器码CODE不一致");
        }

        //计算授权时间
        LocalDateTime now = LocalDateTime.now();
        if (type.equals(1)) {
            now= now.plusDays(1);
        } else if (type.equals(2)) {
            now = now.plusWeeks(1);
        } else if (type.equals(3)) {
            now = now.plusMonths(1);
        } else if (type.equals(4)) {
            now = now.plusYears(1);
        }
        long stopTime = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        //开始写入授权信息
        authorization.setId(authorizationVo.getId());
        authorization.setMac(authorizationVo.getMac());
        authorization.setTime(authorizationVo.getTime());
        authorization.setCreateKeyTime(authorizationVo.getCreateKeyTime());
        authorization.setType(authorizationVo.getType());
        authorization.setStopKeyTime(stopTime);
        authorization.setActivationTime(System.currentTimeMillis());
        authorization.setStatus(true);
        updateById(authorization);
    }

    @Override
    public Authorization parseKey(String key) {
        Assert.hasText(key, "授权码为空");
        //公钥加密
        RSA rsa = new RSA(null, KeyUtil.publicKey);
        String decryptStr = rsa.decryptStr(key, KeyType.PublicKey);
        Assert.hasText(decryptStr, "授权码解析失败");
        Authorization authorization = JSON.parseObject(decryptStr, Authorization.class);
        Assert.notNull(authorization, "授权码转译失败");
        return authorization;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String getLocalKeyAndSave() {
        Authorization authorization = getAll();
        if (authorization==null){
            authorization = new Authorization();
            //生成并保存
            String localMac = getLocalMac();
            Assert.hasText(localMac, "获取机器信息失败!");
            String code = StrUtil.uuid();
            authorization.setTime(System.currentTimeMillis());
            authorization.setCode(code);
            authorization.setMac(localMac);
            authorization.setStatus(false);
            save(authorization);
        }
        RSA rsa = new RSA(null,KeyUtil.publicKey);
        byte[] decrypt = rsa.encrypt(JSON.toJSONBytes(authorization), KeyType.PublicKey);
        //公钥加密
        String encode = Base64.encode(decrypt);
        return encode;
    }
    public Authorization getAll() {
        LambdaQueryWrapper<Authorization> wrapper = new QueryWrapper<Authorization>()
                .lambda()
                .orderByAsc(Authorization::getTime);
        List<Authorization> list = list(wrapper);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }

    @Override
    public Authorization getByIdAndCode(String id, String code, Boolean status) {
        LambdaQueryWrapper<Authorization> wrapper = new QueryWrapper<Authorization>()
                .lambda()
                .eq(Authorization::getId, id)
                .eq(Authorization::getCode, code)
                .eq(Authorization::getStatus, status)
                ;
        return getOne(wrapper);
    }

    @Override
    public Authorization getWebInterceptor() {
        LambdaQueryWrapper<Authorization> wrapper = new QueryWrapper<Authorization>()
                .lambda()
                .eq(Authorization::getStatus,true);
        List<Authorization> list = list(wrapper);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }

    @Override
    public void deleteAuthCode() {
        LambdaQueryWrapper<Authorization> wrapper = new QueryWrapper<Authorization>()
                .lambda();
        remove(wrapper);
    }
}
